package com.ly.heart.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.common.PageParam;
import com.ly.common.core.domain.ActCurrentTaskVo;
import com.ly.common.core.domain.AjaxResult;
import com.ly.common.core.domain.entity.SysDept;
import com.ly.common.core.domain.entity.SysUser;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.DateUtils;
import com.ly.common.utils.SecurityUtils;
import com.ly.common.utils.StringUtils;
import com.ly.common.utils.erp.*;
import com.ly.heart.domain.*;
import com.ly.heart.domain.dto.*;
import com.ly.heart.domain.vo.*;
import com.ly.heart.domain.vo.select.KingPurchaseInventorySelectVo;
import com.ly.heart.domain.vo.select.query.KingInventorySelectQueryDto;
import com.ly.heart.mapper.KingInventoryMapper;
import com.ly.heart.service.*;
import com.ly.heart.util.ChineseToPinyin;
import com.ly.heart.util.CurrentUserUtil;
import com.ly.system.service.ISysDeptService;
import com.ly.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

/**
 * 金蝶-入库/出库单Service业务层处理
 *
 * @author cxl
 * @date 2024-07-13
 */
@Service
public class KingInventoryServiceImpl extends ServiceImpl<KingInventoryMapper, KingInventoryEntity> implements IKingInventoryService {

    @Resource
    private KingInventoryMapper kingInventoryMapper;
    @Resource
    private IKingInventoryMaterialService kingInventoryMaterialService;
    @Resource
    private IKingInventoryMaterialDetailService kingInventoryMaterialDetailService;
    @Resource
    private IKingInventoryMaterialDetailSerialService kingInventoryMaterialDetailSerialService;
    @Resource
    private ISysDeptService sysDeptService;
    @Resource
    private IOrderService orderService;
    @Resource
    private ISaleOrderService saleOrderService;
    @Resource
    private IMaterialDetailService materialDetailService;
    @Resource
    private IActModelService actModelService;
    @Resource
    private IActTaskCommentService actTaskCommentService;
    @Resource
    private IKingRealInventoryService kingRealInventoryService;
    @Resource
    private IKingProcureRefundMaterialService procureRefundMaterialService;
    @Resource
    private IKingInvoicePayableDetailService kingInvoicePayableDetailService;
    @Resource
    private IKingSaleRefundDetailService kingSaleRefundDetailService;
    @Resource
    private IKingInvoiceReceivableDetailService kingInvoiceReceivableDetailService;
    @Resource
    private IKingDiffLogService kingDiffLogService;
    @Resource
    private IMaterialQualityService materialQualityService;
    @Resource
    private IKingCheckMaterialUseDecisionService checkMaterialUseDecisionService;
    @Resource
    private IKingBaseInventoryStatusService kingBaseInventoryStatusService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private IKingBaseBusinessGroupDetailService kingBaseBusinessGroupDetailService;
    @Resource
    private ISupplierContactsService supplierContactsService;
    @Resource
    private IKingBaseContactsService baseContactsService;
    @Resource
    private IKingBaseSettlementTypeService kingBaseSettlementTypeService;
    @Resource
    private IKingBaseCurrencyService kingBaseCurrencyService;
    @Resource
    private IKingBaseReceiptPayConditionService kingBaseReceiptPayConditionService;
    @Resource
    private IKingBaseMeteringUnitService meteringUnitService;
    @Resource
    private ISupplierService supplierService;
    @Resource
    private IKingPurchasePriceService kingPurchasePriceService;
    @Resource
    private IKingBaseExchangeRateTypeService kingBaseExchangeRateTypeService;
    @Resource
    private IKingReceiveNoticeService kingReceiveNoticeService;
    @Resource
    private IKingReceiveNoticeMaterialService kingReceiveNoticeMaterialService;
    @Resource
    private IKingInvoicePayableService iKingInvoicePayableService;
    @Resource
    private IKingInvoiceReceivableService iKingInvoiceReceivableService;
    @Resource
    private IWarehouseService warehouseService;


    @Override
    public AjaxResult getKingInventoryPageListByMaterial ( KingInventoryQueryDto queryDto ) {
        queryDto.setPage ( queryDto.getPage () - 1 );
        List<KingPurchaseInventoryVo> list = kingInventoryMaterialService.getPurchaseInventoryList ( queryDto );
        list.forEach ( inventoryVo -> {
            ActTaskCommentEntity actTaskCommentEntity = actTaskCommentService.queryLastComment ( inventoryVo.getInstanceId () );
            if ( actTaskCommentEntity != null ) {
                inventoryVo.setApprovedUser ( actTaskCommentEntity.getApprovedUser () );
                inventoryVo.setRemark ( actTaskCommentEntity.getRemark () );
            }
            ActCurrentTaskVo currentTaskVo = actModelService.getCurrentTaskByInstanceId ( inventoryVo.getInstanceId () );
            Optional.ofNullable ( currentTaskVo ).ifPresent ( inventoryVo :: setCurrentTask );

            //入库单实际数量
            String receiptsNum = inventoryVo.getReceiptsNum ();
            //入库单价税合计
            String totalTaxPrice = inventoryVo.getTotalTaxPrice ();
            //入库单金额
            String amountMoney = inventoryVo.getAmountMoney ();

            KingInventoryMaterialQueryDto materialQueryDto = new KingInventoryMaterialQueryDto ();
            materialQueryDto.setInventoryId ( inventoryVo.getId () );
            materialQueryDto.setMaterialDetailId ( inventoryVo.getMaterialDetailId () );
            /**累计退货数量（不区分退货方式）**/
            String totalReturnNum = procureRefundMaterialService.getMaterialNumByInventoryIdAndMaterialId ( materialQueryDto );
            inventoryVo.setTotalReturnNum ( totalReturnNum );

            /**累计退货退款数量(采购退料单退货退款数量)**/
            String totalReturnRefundNum = procureRefundMaterialService.getReturnNumByInventoryIdAndMaterialId ( materialQueryDto );
            inventoryVo.setTotalReturnRefundNum ( totalReturnRefundNum );

            /**累计退货补货价税合计(采购退料单退货补货价税合计)**/
            String totalReturnReplenishTotalPriceTax = procureRefundMaterialService.getReturnReplenishTotalPriceTaxByInventoryIdAndMaterialId ( materialQueryDto );
            inventoryVo.setTotalReturnReplenishTotalPriceTax ( totalReturnReplenishTotalPriceTax );

            /**累计应付统计结果**/
            //1.源单类型为采购入库单的应付单数量和金额统计
            OrderSumResult totalPayableResult = kingInvoicePayableDetailService.getNumAndTotalTaxPriceByInventory ( materialQueryDto );
            //2.源单类型为采购入库单的应付单数量
            String totalPayableResultNum = totalPayableResult.getTotalNum ();
            //3.先查询源单类型为采购入库单的应付单集合
            List<KingInvoicePayableDetailEntity> payableDetailListByInventory = kingInvoicePayableDetailService.getInvoicePayableDetailListByInventory ( materialQueryDto );
            //4.过滤出此入库单应付单的物料明细id
            //         List<String> totalPayableDetailIdList = payableDetailListByInventory.stream().filter(Objects::nonNull).map(KingInvoicePayableDetailEntity::getId).collect(Collectors.toList());
            //5.【红冲单】查询出源单明细为上面物料明细id集合的应付红冲单
            //           List<KingInvoicePayableDetailEntity> redPayableDetailList = kingInvoicePayableDetailService.list(new LambdaQueryWrapper<KingInvoicePayableDetailEntity>().in(KingInvoicePayableDetailEntity::getSourceMaterialDetailId, totalPayableDetailIdList));
            //6.【红冲单】计算红冲单的数量
            double sumRedNum = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( payableDetail -> Double.parseDouble ( payableDetail.getNum () ) ).sum ();
            //7.累计应付数量=源单类型为采购入库单的应付单数量+红冲单
            String totalPayableNum = CommonUtil.sumStr ( totalPayableResultNum, String.valueOf ( sumRedNum ), 2 );
            inventoryVo.setTotalPayableNum ( totalPayableNum );
            //1.先获取源单类型为采购入库单的应付单价税合计
            String totalPayableResultAmount = totalPayableResult.getTotalAmount ();
            //2.计算红冲单的价税合计
            double sumRedTotalTaxPrice = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( redDetail -> Double.parseDouble ( redDetail.getTotalTaxPrice () ) ).sum ();
            //3.累计应付价税合计 = 源单类型为采购入库单的应付单价税合计+红冲单价税合计
            String totalPayableTotalPriceTax = CommonUtil.sumStr ( totalPayableResultAmount, String.valueOf ( sumRedTotalTaxPrice ), 2 );
            inventoryVo.setTotalPayableTotalPriceTax ( totalPayableTotalPriceTax );

            /**剩余应付统计结果**/
            //剩余应付数量(入库数量-累计应付数量)
            String surplusPayableNum = CommonUtil.subStr ( receiptsNum, totalPayableNum, 2 );
            inventoryVo.setSurplusPayableNum ( surplusPayableNum );
            //剩余应付价税合计(价税合计-累计应付价税合计)
            String surplusPayableTotalPriceTax = CommonUtil.subStr ( totalTaxPrice, totalPayableTotalPriceTax, 2 );
            inventoryVo.setSurplusPayableTotalPriceTax ( surplusPayableTotalPriceTax );

            /**累计应付单对应源单统计结果**/
            //累计应付单对应源单金额(应付单源单类型为出库单求和+红冲单金额)
            double originTaxAmount = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( originDetail -> Optional.ofNullable ( originDetail.getNotTaxAmount () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ();
            double redTaxAmount = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( redDetail -> Optional.ofNullable ( redDetail.getNotTaxAmount () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ();
            String totalPayableSourceDocAmount = CommonUtil.sumStr ( String.valueOf ( originTaxAmount ), String.valueOf ( redTaxAmount ), 2 );
            inventoryVo.setTotalPayableSourceDocAmount ( totalPayableSourceDocAmount );
            //剩余应付单对应源单金额(金额-累计应付单对应源单金额)
            String surplusPayableSourceDocAmount = CommonUtil.subStr ( amountMoney, totalPayableSourceDocAmount, 2 );
            inventoryVo.setSurplusPayableSourceDocAmount ( surplusPayableSourceDocAmount );
            //累计应付单对应源单价税合计(应付单源单类型为出库单求和+红冲单价税合计)
//            double originTotalTaxPrice = payableDetailListByInventory.stream().filter(Objects::nonNull).mapToDouble(originDetail -> Double.parseDouble(originDetail.getTotalTaxPrice())).sum();
            double redTotalTaxPrice = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( redDetail -> Double.parseDouble ( redDetail.getTotalTaxPrice () ) ).sum ();
            String totalPayableSourceDocTotalPriceTax = CommonUtil.sumStr ( totalPayableResult.getTotalAmount (), String.valueOf ( redTotalTaxPrice ), 2 );
            inventoryVo.setTotalPayableSourceDocTotalPriceTax ( totalPayableSourceDocTotalPriceTax );
            //剩余应付单对应源单价税合计(价税合计-累计应付单对应源单价税合计)
            String surplusPayableSourceDocTotalPriceTax = CommonUtil.subStr ( totalTaxPrice, totalPayableSourceDocTotalPriceTax, 2 );
            inventoryVo.setSurplusPayableSourceDocTotalPriceTax ( surplusPayableSourceDocTotalPriceTax );

            /**成本统计结果(差异日志中此入库单中此物料明细本月记录)**/
            QueryWrapper<KingDiffLogEntity> diffLogQuery = Wrappers.query ();
            diffLogQuery.eq ( "doc_no", inventoryVo.getDocCode () );
            diffLogQuery.eq ( "source_material_detail_id", inventoryVo.getMaterialDetailId () );
            int inventoryYear = inventoryVo.getInventoryTime ().getYear () + 1900;
            int inventoryMonth = inventoryVo.getInventoryTime ().getMonth () + 1;
            diffLogQuery.apply ( "YEAR(verify_date) = " + inventoryYear + " AND MONTH(verify_date) = " + inventoryMonth );
            List<KingDiffLogEntity> diffLogList = kingDiffLogService.list ( diffLogQuery );

//            //入库当月运费成本【实际分配标准为金额本位币的勾稽金额合计】
//            List<KingDiffLogEntity> freightCostList = diffLogList.stream().filter(Objects::nonNull).filter(diffLog -> diffLog.getActualAllocationStandards().equals(KingConstUtil.AMOUNT_CURRENCY)).collect(Collectors.toList());
//            String warehousingCurrentMonthFreightCost = String.valueOf( freightCostList.stream().filter(Objects::nonNull).mapToDouble(kingDiffLog -> Optional.ofNullable(kingDiffLog.getVerifyAmount()).map(Double::parseDouble).orElse(0.0)).sum());
//            inventoryVo.setWarehousingCurrentMonthFreightCost(warehousingCurrentMonthFreightCost);
//
//            //当月物料成本(实际核销标准不为金额本位币的数据)【实际分配标准不为金额本位币的勾稽金额合计 + 入库单金额？】
//            List<KingDiffLogEntity> materialCostList = diffLogList.stream().filter(Objects::nonNull).filter(diffLog -> !diffLog.getActualAllocationStandards().equals(KingConstUtil.AMOUNT_CURRENCY)).collect(Collectors.toList());
//            String materialCost = String.valueOf(materialCostList.stream().filter(Objects::nonNull).mapToDouble(kingDiffLog -> Double.parseDouble(kingDiffLog.getVerifyAmount())).sum());
//            String currentMonthMaterialCost = CommonUtil.sumStr(materialCost, amountMoney, 2);
//            inventoryVo.setCurrentMonthMaterialCost(currentMonthMaterialCost);
//
//            //当月总成本【入库当月运费成本+当月物料成本】
//            String currentMonthTotalCost = CommonUtil.sumStr(warehousingCurrentMonthFreightCost, currentMonthMaterialCost, 2);
//            inventoryVo.setCurrentMonthTotalCost(currentMonthTotalCost);
//
//            //当月单位成本【当月总成本/入库数量】
//            String currentMonthUnitCost = CommonUtil.divisionStr(currentMonthTotalCost, receiptsNum, 10);
//            inventoryVo.setCurrentMonthUnitCost(currentMonthUnitCost);
//
//            //入库当月运费成本(本位币)【实际分配标准为金额本位币的勾稽金额本位币合计】
//            String warehousingCurrentMonthFreightCostBase = String.valueOf(freightCostList.stream().filter(Objects::nonNull).mapToDouble(kingDiffLog -> Double.parseDouble(kingDiffLog.getVerifyAmountCurrency())).sum());
//            inventoryVo.setWarehousingCurrentMonthFreightCostBase(warehousingCurrentMonthFreightCostBase);
//
//            //当月物料成本(本位币)【实际分配标准不为金额本位币的勾稽金额本位币合计 + 入库单金额本位币】
//            String materialCostBase = String.valueOf(materialCostList.stream().filter(Objects::nonNull).mapToDouble(kingDiffLog -> Double.parseDouble(kingDiffLog.getVerifyAmountCurrency())).sum());
//            String currentMonthMaterialCostBase = CommonUtil.sumStr(materialCostBase, inventoryVo.getAmountMoneyBase(), 2);
//            inventoryVo.setCurrentMonthMaterialCostBase(currentMonthMaterialCostBase);

            // 过滤出实际分配标准为金额本位币的运费数据
            List<KingDiffLogEntity> freightCostList = diffLogList.stream ().filter ( Objects :: nonNull ).filter ( diffLog -> KingConstUtil.AMOUNT_CURRENCY.equals ( diffLog.getActualAllocationStandards () ) ).collect ( Collectors.toList () );

            // 计算当月运费成本
            String warehousingCurrentMonthFreightCost = String.valueOf ( freightCostList.stream ().filter ( Objects :: nonNull ).mapToDouble ( kingDiffLog ->
                    Optional.ofNullable ( kingDiffLog.getVerifyAmount () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ()
            );
            inventoryVo.setWarehousingCurrentMonthFreightCost ( warehousingCurrentMonthFreightCost );

            // 过滤出实际分配标准不为金额本位币的物料成本数据
            List<KingDiffLogEntity> materialCostList = diffLogList.stream ().filter ( Objects :: nonNull ).filter ( diffLog -> ! KingConstUtil.AMOUNT_CURRENCY.equals ( diffLog.getActualAllocationStandards () ) ).collect ( Collectors.toList () );

            // 计算当月物料成本
            String materialCost = String.valueOf ( materialCostList.stream ().filter ( Objects :: nonNull ).mapToDouble ( kingDiffLog ->
                    Optional.ofNullable ( kingDiffLog.getVerifyAmount () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ()
            );
            String currentMonthMaterialCost = CommonUtil.sumStr ( materialCost, amountMoney, 2 );
            inventoryVo.setCurrentMonthMaterialCost ( currentMonthMaterialCost );

            // 计算当月总成本
            String currentMonthTotalCost = CommonUtil.sumStr ( warehousingCurrentMonthFreightCost, currentMonthMaterialCost, 2 );
            inventoryVo.setCurrentMonthTotalCost ( currentMonthTotalCost );

            // 计算当月单位成本
            String currentMonthUnitCost = CommonUtil.divisionStr ( currentMonthTotalCost, receiptsNum, 10 );
            inventoryVo.setCurrentMonthUnitCost ( currentMonthUnitCost );

            // 计算入库当月运费成本（本位币）
            String warehousingCurrentMonthFreightCostBase = String.valueOf ( freightCostList.stream ().filter ( Objects :: nonNull ).mapToDouble ( kingDiffLog ->
                    Optional.ofNullable ( kingDiffLog.getVerifyAmountCurrency () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ()
            );
            inventoryVo.setWarehousingCurrentMonthFreightCostBase ( warehousingCurrentMonthFreightCostBase );
            // 计算当月物料成本（本位币）
            String materialCostBase = String.valueOf ( materialCostList.stream ().filter ( Objects :: nonNull ).mapToDouble ( kingDiffLog ->
                    Optional.ofNullable ( kingDiffLog.getVerifyAmountCurrency () ).map ( Double :: parseDouble ).orElse ( 0.0 ) ).sum ()
            );
            String currentMonthMaterialCostBase = CommonUtil.sumStr ( materialCostBase, inventoryVo.getAmountMoneyBase (), 2 );
            inventoryVo.setCurrentMonthMaterialCostBase ( currentMonthMaterialCostBase );

            //当月总成本(本位币)【入库当月运费成本(本位币) + 当月物料成本(本位币)】
            String currentMonthTotalCostBase = CommonUtil.sumStr ( warehousingCurrentMonthFreightCostBase, currentMonthMaterialCostBase, 2 );
            inventoryVo.setCurrentMonthTotalCostBase ( currentMonthTotalCostBase );

            //当月单位成本(本位币)【当月总成本(本位币) / 入库数量】
            String currentMonthUnitCostBase = CommonUtil.divisionStr ( currentMonthTotalCostBase, receiptsNum, 2 );
            inventoryVo.setCurrentMonthUnitCostBase ( currentMonthUnitCostBase );
        } );
        Integer totalCount = kingInventoryMaterialService.queryTotalCount ( queryDto );
        PageParam records = new PageParam ();
        records.setRecords ( list ).setTotal ( totalCount );
        return AjaxResult.success ( records );
    }


    @Override
    public AjaxResult getKingSaleOutInventoryPageList ( KingInventoryQueryDto queryDto ) {
        queryDto.setPage ( ( queryDto.getPage () - 1 ) * queryDto.getLimit () );
        List<KingSaleOutInventoryVo> saleOutInventoryList = kingInventoryMaterialService.getSaleOutInventoryList ( queryDto );
        for ( KingSaleOutInventoryVo saleInventory : saleOutInventoryList ) {
            if ( StringUtils.isNotEmpty ( saleInventory.getInstanceId () ) ) {
                ActTaskCommentEntity actTaskCommentEntity = actTaskCommentService.queryLastComment ( saleInventory.getInstanceId () );
                if ( actTaskCommentEntity != null ) {
                    saleInventory.setApprovedUser ( actTaskCommentEntity.getApprovedUser () );
                    saleInventory.setRemark ( actTaskCommentEntity.getRemark () );
                }
                ActCurrentTaskVo currentTaskVo = actModelService.getCurrentTaskByInstanceId ( saleInventory.getInstanceId () );
                Optional.ofNullable ( currentTaskVo ).ifPresent ( saleInventory :: setCurrentTask );
            }
            KingSaleOutInventoryMaterialQueryDto saleOutInventoryMaterialQueryDto = new KingSaleOutInventoryMaterialQueryDto ();
            saleOutInventoryMaterialQueryDto.setInventoryId ( saleInventory.getId () );
            saleOutInventoryMaterialQueryDto.setMaterialDetailId ( saleInventory.getMaterialDetailId () );
            //累计退货补货数量
            KingSaleRefundDetailEntity kingSaleRefundTotalNumAndTaxPrice = kingSaleRefundDetailService.getKingSaleRefundTotalNumAndTaxPrice ( saleOutInventoryMaterialQueryDto );
            saleInventory.setTotalReturnNum ( kingSaleRefundTotalNumAndTaxPrice.getTotalReturnNum () );
            saleOutInventoryMaterialQueryDto.setType ( ConstUtil.SALE_REFUND_TYPE_REFUND_AND_REPLACE );
            //累计退货补货数量,累计退货补货价税合计
            KingSaleRefundDetailEntity refundTypeRefundAndReplace = kingSaleRefundDetailService.getKingSaleRefundTotalNumAndTaxPrice ( saleOutInventoryMaterialQueryDto );
            saleInventory.setTotalReturnReplenishNum ( refundTypeRefundAndReplace.getTotalReturnNum () );
            saleInventory.setTotalReturnReplenishTaxPrice ( refundTypeRefundAndReplace.getTotalReturnTaxPrice () );
            //累计应收数量,累计应收价税合计=应收单单源单类型为出库单及源单行号求和，另外加上财务红冲单金额。
            saleOutInventoryMaterialQueryDto.setType ( String.valueOf ( KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_OUT_STORAGE ) );
            //源单类型为出库单
            KingInvoiceReceivableDetailEntity kingInvoiceReceivableDetailEntity = kingInvoiceReceivableDetailService.selectReceivableSumByOutStorageNo ( saleOutInventoryMaterialQueryDto );
            String totalNumReceivable = kingInvoiceReceivableDetailEntity.getTotalNumReceivable ();//源单类型出库单累计数量
            String OutTotalTaxPriceReceivable = kingInvoiceReceivableDetailEntity.getTotalTaxPriceReceivable ();//源单类型出库单累计价税合计
            String OutTotalNotTaxAmountReceivable = kingInvoiceReceivableDetailEntity.getTotalNotTaxAmountReceivable ();//源单类型出库单的金额
            //源单类型财务红冲单
            saleOutInventoryMaterialQueryDto.setType ( String.valueOf ( KingConstUtil.RECEIVABLE_SOURCE_DOC_TYPE_PAYABLE ) );
            KingInvoiceReceivableDetailEntity kingInvoiceReceivableDetail = kingInvoiceReceivableDetailService.selectReceivableSumByOutStorageNo ( saleOutInventoryMaterialQueryDto );
            String HCTotalNotTaxAmountReceivable = kingInvoiceReceivableDetail.getTotalNotTaxAmountReceivable ();//源单类型红冲的金额
            String HCTotalTaxPriceReceivable = kingInvoiceReceivableDetail.getTotalTaxPriceReceivable ();//源单类型红冲的价税合计
            //累计应收数量,累计应收价税合计
            saleInventory.setTotalNumReceivable ( CommonUtil.sumStr ( totalNumReceivable, kingInvoiceReceivableDetail.getTotalNumReceivable (), 2 ) );
            saleInventory.setTotalTaxPriceReceivable ( CommonUtil.subStr ( OutTotalTaxPriceReceivable, HCTotalNotTaxAmountReceivable, 2 ) );
            //剩余应收数量=出库数量-累计应收数量,剩余应收价税合计=价税合计-累计应收价税合计
            saleInventory.setSurplusNumReceivable ( CommonUtil.subStr ( saleInventory.getReceiptsNum (), saleInventory.getTotalNumReceivable (), 2 ) );
            saleInventory.setSurplusTaxPriceReceivable ( CommonUtil.subStr ( saleInventory.getTotalTaxPrice (), saleInventory.getTotalTaxPriceReceivable (), 2 ) );
            //todo 累计应收单对应源单金额,剩余应收单对应源单金额,累计应付单对应源单价税合计,剩余应付单对应源单金额价税合计
            //累计应付单对应源单金额=应付单单源单类型为出库单及源单行号求和，另外加上财务红冲单金额。
            saleInventory.setTotalTaxPricePayable ( CommonUtil.sumStr ( OutTotalNotTaxAmountReceivable, HCTotalNotTaxAmountReceivable, 2 ) );
            //剩余应收单对应源单金额=金额-累计应付单对应源单金额
            saleInventory.setSurplusNumReceivable ( CommonUtil.subStr ( saleInventory.getAmountMoney (), saleInventory.getTotalTaxPricePayable (), 2 ) );
            //累计应付单对应源单价税合计=应付单单源单类型为出库单及源单行号求和，另外加上财务红冲单价税合计。
            saleInventory.setTotalTaxPricePayableBase ( CommonUtil.sumStr ( OutTotalTaxPriceReceivable, HCTotalTaxPriceReceivable, 2 ) );
            //剩余应付单对应源单金额价税合计=价税合计-累计应付单对应源单价税合计
            saleInventory.setSurplusTaxPricePayable ( CommonUtil.subStr ( saleInventory.getTotalTaxPriceBase (), saleInventory.getTotalTaxPricePayableBase (), 2 ) );
        }
        Integer count = kingInventoryMaterialService.getSaleOutInventoryCount ( queryDto );
        PageParam records = new PageParam ();
        records.setRecords ( saleOutInventoryList ).setTotal ( count );
        return AjaxResult.success ( records );
    }

    /**
     * 封装公用模糊查询方法
     *
     * @param queryDto
     * @return
     */
    private QueryWrapper<KingInventoryEntity> baseQuery ( KingInventoryQueryDto queryDto ) {
        QueryWrapper<KingInventoryEntity> query = Wrappers.query ();
        //根据单号查询
        if ( StringUtils.isEmpty ( queryDto.getDocCode () ) ) {
            query.like ( "doc_code", queryDto.getDocCode () );
        }
        //根据货主查询
        if ( ! StringUtils.isEmpty ( queryDto.getCargoOwner () ) ) {
            query.eq ( "cargo_owner", queryDto.getCargoOwner () );
        }
        return query;
    }

    /**
     * 暂存采购入库单
     *
     * @param kingInventory 金蝶-入库/出库单
     * @return 结果
     */
    @Override
    @Transactional ( rollbackFor = Exception.class )
    public AjaxResult draftKingInventory ( KingInventoryEntity kingInventory ) {
        if ( StringUtils.isEmpty ( kingInventory.getId () ) ) {
            String inventoryId = SnowflakeIdWorker.getInstance ().nextStringId ();
            Date nowDate = DateUtils.getNowDate ();
            String userId = SecurityUtils.getLoginUser ().getUser ().getUserId ();
            //设置采购入库单基本信息
            kingInventory.setId ( inventoryId ).setCreateTime ( nowDate ).setUserId ( userId ).setIsSend ( KingConstUtil.KING_DATA_IS_SEND_NO ).setType ( ConstUtil.KING_INVENTORY_TYPE_IN ).setChildTye ( ConstUtil.KING_INVENTORY_TYPE_IN_PURCHASE );
            //采购入库单单号生成
            if ( StringUtils.isEmpty ( kingInventory.getDocCode () ) ) {
                String companyId = CurrentUserUtil.getCompanyId ();
                SysDept sysDept = sysDeptService.getById ( companyId );
                Integer count = kingInventoryMapper.queryCount ( ConstUtil.KING_INVENTORY_TYPE_IN );
                String countStr = String.format ( "%06d", count );
                String firstLetter = ChineseToPinyin.getFirstLetter ( sysDept.getDeptName () );
                String docCode = firstLetter.concat ( "_CGRK_" ).concat ( countStr );
                kingInventory.setDocCode ( docCode );
            }
            //判断物料明细数量和金额
            List<KingInventoryMaterialEntity> materialLists = kingInventory.getMaterialLists ();
            //新增物料明细信息
            if ( ! CollectionUtils.isEmpty ( materialLists ) ) {
                saveMaterialAndDetail ( kingInventory, materialLists, "采购入库单暂存" );
            }
            //计算总表三个金额(税额 金额 价税合计)
            double taxAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTaxAmount () ) ? "0" : detail.getTaxAmount () ) ).sum ();
            double moneyAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getMoneyAmount () ) ? "0" : detail.getMoneyAmount () ) ).sum ();
            double totalTaxPrice = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTotalTaxPrice () ) ? "0" : detail.getTotalTaxPrice () ) ).sum ();
            kingInventory.setTaxAmount ( String.valueOf ( taxAmount ) );
            kingInventory.setMoneyAmount ( String.valueOf ( moneyAmount ) );
            kingInventory.setTotalPriceTax ( String.valueOf ( totalTaxPrice ) );
            //设置货主类型以及货主
            kingInventory.setCargoOwnerType("BD_OwnerOrg");
            kingInventory.setCargoOwner("100");
            //流程状态：暂存
            kingInventory.setState ( ConstUtil.STATE_IN_DRAFT );
            boolean saveFlag = this.save ( kingInventory );
            if ( saveFlag ) {
                return AjaxResult.success ( "暂存采购入库单成功！", kingInventory.getId () );
            }
            return AjaxResult.error ( "暂存采购入库单失败！" );
        } else {
            return updateKingInventory ( kingInventory );
        }
    }

    /**
     * 逻辑：供应商、币别、采购组织不同不得合并下推；
     * 数量和金额都不能超采购订单；
     *
     * @param kingInventory
     * @return
     */
    @Override
    @Transactional ( rollbackFor = Exception.class )
    public AjaxResult submitKingInventory ( KingInventoryEntity kingInventory ) {
        if ( StringUtils.isBlank ( kingInventory.getId () ) ) {
            return AjaxResult.error ( "请先暂存该单据！" );
        }
        if ( Objects.isNull ( kingInventory.getModelId () ) ) {
            return AjaxResult.error ( "审批流程modelId不能为空！" );
        }
        //判断物料明细
        if ( CollectionUtils.isEmpty ( kingInventory.getMaterialLists () ) ) {
            return AjaxResult.error ( "物料信息不能为空！" );
        }
        //校验物料明细
        List<KingInventoryMaterialEntity> materialLists = kingInventory.getMaterialLists ();
        materialLists.forEach ( inventoryMaterial -> {
            if ( StringUtils.isNotEmpty ( inventoryMaterial.getSourceType () ) ) {
                //采购订单下推
                if ( inventoryMaterial.getSourceType ().equals ( ConstUtil.INVENTORY_SOURCE_TYPE_ORDER ) ) {
                    MaterialQualityEntity mustCheck = materialQualityService.getOne ( new LambdaQueryWrapper<MaterialQualityEntity> ().eq ( MaterialQualityEntity :: getMaterialId, inventoryMaterial.getMaterialId () ) );
                    if ( Objects.nonNull ( mustCheck ) && mustCheck.getFCheckIncoming ().equals ( "1" ) ) {
                        throw new CustomException ( "物料勾选来料检验,必须通过收料通知单下推！" );
                    }
                    //过滤采购订单id集合
                    List<String> orderIdList = materialLists.stream ().filter ( Objects :: nonNull ).distinct ().map ( KingInventoryMaterialEntity :: getRelationId ).collect ( Collectors.toList () );
                    List<OrderEntity> orderList = orderService.list ( new LambdaQueryWrapper<OrderEntity> ().in ( OrderEntity :: getId, orderIdList ) );
                    //判断供应商是否不同
                    List<String> supplierIdList = orderList.stream ().filter ( Objects :: nonNull ).distinct ().map ( OrderEntity :: getSupplierId ).collect ( Collectors.toList () );
                    if ( ! supplierIdList.isEmpty () && supplierIdList.size () >= 2 ) {
                        throw new CustomException ( "所选单据供应商不一致，无法操作！" );
                    }
                    //判断采购组织是否不同
                    List<String> purchaseOrgList = orderList.stream ().filter ( Objects :: nonNull ).distinct ().map ( OrderEntity :: getPurchaseOrg ).collect ( Collectors.toList () );
                    if ( ! purchaseOrgList.isEmpty () && purchaseOrgList.size () >= 2 ) {
                        throw new CustomException ( "所选单据采购组织不一致，无法操作！" );
                    }
                    //判断币别是否不同
                    List<String> settlementCurrencyList = orderList.stream ().filter ( Objects :: nonNull ).distinct ().map ( OrderEntity :: getSettlementCurrency ).collect ( Collectors.toList () );
                    if ( ! settlementCurrencyList.isEmpty () && settlementCurrencyList.size () >= 2 ) {
                        throw new CustomException ( "所选单据结算币别不一致，无法操作！" );
                    }
                    checkMaterialNumAndAmountByOrder ( inventoryMaterial );
                }
                //收料通知单下推
                if ( inventoryMaterial.getSourceType ().equals ( ConstUtil.INVENTORY_SOURCE_TYPE_RECEIVE_NOTICE ) ) {
                    checkMaterialNumByReceiveNotice ( inventoryMaterial );
                }
            }
        } );
        //先删除暂存时保存的物料明细信息
        removeMaterialAndDetail ( kingInventory.getId () );
        //保存物料等信息
        saveMaterialAndDetail ( kingInventory, materialLists, "采购入库单提交" );
        //计算总表三个金额
        double taxAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTaxAmount () ) ? "0" : detail.getTaxAmount () ) ).sum ();
        double moneyAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getMoneyAmount () ) ? "0" : detail.getMoneyAmount () ) ).sum ();
        double totalTaxPrice = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTotalTaxPrice () ) ? "0" : detail.getTotalTaxPrice () ) ).sum ();
        kingInventory.setTaxAmount ( String.valueOf ( taxAmount ) );
        kingInventory.setMoneyAmount ( String.valueOf ( moneyAmount ) );
        kingInventory.setTotalPriceTax ( String.valueOf ( totalTaxPrice ) );
        //启动审批流程
        StartProcessDto startDto = new StartProcessDto ().setBusinessId ( kingInventory.getId () ).setBusinessType ( kingInventory.getBusinessType () ).setModelId ( kingInventory.getModelId () );
        startDto.setBusinessName ( "采购入库单_".concat ( kingInventory.getDocCode () ) );
        String instanceId = actModelService.startProcess ( startDto );
        kingInventory.setState ( ConstUtil.STATE_IN_PROCESS ).setInstanceId ( instanceId );
        boolean updated = this.updateById ( kingInventory );
        if ( ! updated ) {
            return AjaxResult.error ( "提交采购入库单失败!" );
        }
        return AjaxResult.success ( "提交采购入库单成功!" );
    }

    @Override
    @Transactional ( rollbackFor = Exception.class )
    public AjaxResult updateKingInventory ( KingInventoryEntity kingInventory ) {
        if ( StringUtils.isEmpty ( kingInventory.getId () ) ) {
            return AjaxResult.error ( "采购入库单id不能为空！" );
        }
        //先删除暂存时保存的物料明细信息
        removeMaterialAndDetail ( kingInventory.getId () );
        //判断物料明细数量和金额
        List<KingInventoryMaterialEntity> materialLists = kingInventory.getMaterialLists ();
        //新增物料明细信息
        if ( ! CollectionUtils.isEmpty ( materialLists ) ) {
            saveMaterialAndDetail ( kingInventory, materialLists, "采购入库单修改" );
        }
        //计算总表三个金额
        double taxAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTaxAmount () ) ? "0" : detail.getTaxAmount () ) ).sum ();
        double moneyAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getMoneyAmount () ) ? "0" : detail.getMoneyAmount () ) ).sum ();
        double totalTaxPrice = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTotalTaxPrice () ) ? "0" : detail.getTotalTaxPrice () ) ).sum ();
        kingInventory.setTaxAmount ( String.valueOf ( taxAmount ) );
        kingInventory.setMoneyAmount ( String.valueOf ( moneyAmount ) );
        kingInventory.setTotalPriceTax ( String.valueOf ( totalTaxPrice ) );
        //修改主表信息
        boolean updated = this.updateById ( kingInventory );
        if ( ! updated ) {
            return AjaxResult.error ( "修改失败!" );
        }
        return AjaxResult.success ( "修改成功!", kingInventory.getId () );
    }

    /**
     * 采购订单下推采购入库单
     * 1.查询该采购订单该物料是否有已经入库的数量，总计不能超采购订单数量；同时需要查询该采购订单是否有下推收料通知单的数量
     * 2.查询该采购订单该物料是否有已经入库的金额，总计不能超采购订单金额；
     * @param
     */
    private KingInventoryMaterialEntity checkMaterialNumAndAmountByOrder ( KingInventoryMaterialEntity inventoryMaterial ) {
        //1.检查源单物料明细行id
        if ( Objects.nonNull ( inventoryMaterial.getSourceMaterialDetailId () ) ) {
            //2.查询源单采购订单里该物料明细原始数量和金额
            MaterialDetailEntity orderDetail = materialDetailService.getById ( inventoryMaterial.getSourceMaterialDetailId () );
            double orderNumber = Double.parseDouble ( orderDetail.getNumber () );
            BigDecimal orderAmountMoney = new BigDecimal ( orderDetail.getAmountMoney () );
            //3.查询源单采购订单该物料已经形成入库单的数量和金额
            List<KingInventoryMaterialEntity> inventoryMaterials = kingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().ne ( KingInventoryMaterialEntity :: getInventoryId, inventoryMaterial.getInventoryId () ).eq ( KingInventoryMaterialEntity :: getRelationId, inventoryMaterial.getRelationId () ).eq ( KingInventoryMaterialEntity :: getSourceMaterialDetailId, inventoryMaterial.getSourceMaterialDetailId () ) );
            double sumReceiptsNum = 0;
            BigDecimal totalMoneyAmount = BigDecimal.ZERO;
            if ( ! CollectionUtils.isEmpty ( inventoryMaterials ) ) {
                //4.计算该物料已经入库的数量总和
                sumReceiptsNum = inventoryMaterials.stream ().mapToDouble ( hasInventoryMaterial -> Double.parseDouble ( hasInventoryMaterial.getReceiptsNum () ) ).sum ();
                //5.计算该物料已经入库的总金额
                totalMoneyAmount = inventoryMaterials.stream ().filter ( Objects :: nonNull ).map ( KingInventoryMaterialEntity :: getMoneyAmount ).filter ( Objects :: nonNull ).map ( BigDecimal :: new ).reduce ( BigDecimal.ZERO, BigDecimal :: add );
            }
            //6.查询源单采购订单该物料是否有下推收料通知单的数量
            List<KingReceiveNoticeMaterialEntity> receiveNoticeMaterials = kingReceiveNoticeMaterialService.list ( new LambdaQueryWrapper<KingReceiveNoticeMaterialEntity> ().eq ( KingReceiveNoticeMaterialEntity :: getRelationId, inventoryMaterial.getRelationId () ).eq ( KingReceiveNoticeMaterialEntity :: getSourceMaterialDetailId, inventoryMaterial.getSourceMaterialDetailId () ) );
            double sumReceiveNum = 0;
            BigDecimal totalReceiveMoneyAmount = BigDecimal.ZERO;
            if ( ! CollectionUtils.isEmpty ( receiveNoticeMaterials ) ) {
                //7.计算该物料已经形成收料通知单的数量总和
                sumReceiveNum = receiveNoticeMaterials.stream ().mapToDouble ( receiveMaterial -> Double.parseDouble ( receiveMaterial.getDeliveryNum () ) ).sum ();
                //8.计算该物料已经形成收料通知的总金额
                totalReceiveMoneyAmount = receiveNoticeMaterials.stream ().filter ( Objects :: nonNull ).map ( KingReceiveNoticeMaterialEntity :: getMoneyAmount ).filter ( Objects :: nonNull ).map ( BigDecimal :: new ).reduce ( BigDecimal.ZERO, BigDecimal :: add );
            }
            //9.计算剩余可引用数量
            double surplusNum = orderNumber - sumReceiptsNum - sumReceiveNum;
            if ( Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) > surplusNum ) {
                throw new CustomException ( "引用数量不能超过采购订单数量！" );
            }
            //10.计算剩余可引用金额
            BigDecimal surplusAmountMoney = orderAmountMoney.subtract ( totalMoneyAmount ).subtract ( totalReceiveMoneyAmount );
            if ( StringUtils.isNotEmpty ( inventoryMaterial.getMoneyAmount () ) ) {
                int comparisonResult = new BigDecimal(inventoryMaterial.getMoneyAmount ()).compareTo(surplusAmountMoney);
                if(comparisonResult > 0){
                    throw new CustomException ( "引用金额不能超过采购订单金额！" );
                }
            }
            //11.平账操作
            if ( Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) == surplusNum ) {
                BigDecimal price = inventoryMaterial.getPrice () == null ?  new BigDecimal ( inventoryMaterial.getPrice ()) : BigDecimal.ZERO;
                BigDecimal surplusTotalTaxPrice = inventoryMaterial.getTotalTaxPrice () == null ? new BigDecimal ( inventoryMaterial.getTotalTaxPrice () ) : BigDecimal.ZERO;
                //12.采购订单该物料明细原始的价税合计
                String orderTotalTaxPrice = orderDetail.getTotalTaxPrice ();
                if ( ! CollectionUtils.isEmpty ( inventoryMaterials ) ) {
                    //13.查询该物料明细已经形成采购入库单的价税合计
                    BigDecimal inventoryMaterialTotalTaxPrice = inventoryMaterials.stream ().filter ( Objects :: nonNull ).map ( materialDetail -> new BigDecimal ( materialDetail.getTotalTaxPrice () ) ).reduce ( BigDecimal.ZERO, BigDecimal :: add );
                    //14.计算剩余的价税合计(原始物料明细的价税合计 ➖ 已经形成采购入库单的价税合计)
                    surplusTotalTaxPrice = new BigDecimal ( orderTotalTaxPrice ).subtract ( inventoryMaterialTotalTaxPrice );
                }
                if ( CollectionUtils.isEmpty ( receiveNoticeMaterials ) ) {
                    //15.如果有形成的收料通知单明细，需要减去收料通知单的价税合计
                    BigDecimal receiveNoticeMaterialTotalTaxPrice = inventoryMaterials.stream ().filter ( Objects :: nonNull ).map ( materialDetail -> new BigDecimal ( materialDetail.getTotalTaxPrice () ) ).reduce ( BigDecimal.ZERO, BigDecimal :: add );
                    surplusTotalTaxPrice = surplusTotalTaxPrice.subtract ( receiveNoticeMaterialTotalTaxPrice );
                }
                //16.平价，计算单价(剩余的价税合计(订单总价税合计-已生成入库单价税合计-已生成收料通知单价税合计) / 此次数量)
                price = surplusTotalTaxPrice.divide ( new BigDecimal ( inventoryMaterial.getReceiptsNum () ), BigDecimal.ROUND_HALF_UP );
                //17.将值赋值给原字段
                inventoryMaterial.setPrice ( String.valueOf ( price ) );
                inventoryMaterial.setTotalTaxPrice ( String.valueOf ( surplusTotalTaxPrice ) );
            }
        }
        return inventoryMaterial;
    }

    /**
     * 收料通知单下推采购入库单
     * 收料通知单：检验合格和让步接收的都可以下推
     *
     * @param inventoryMaterial
     * @return
     */
    private KingInventoryMaterialEntity checkMaterialNumByReceiveNotice ( KingInventoryMaterialEntity inventoryMaterial ) {
        if ( Objects.nonNull ( inventoryMaterial.getSourceMaterialDetailId () ) ) {
            //根据选择的收料通知单id和物料明细id获取检验合格以及让步接收的数量
            List<KingCheckMaterialUseDecisionEntity> decisionList = queryCheckMaterialByReceiveNotice ( inventoryMaterial.getRelationId (), inventoryMaterial.getSourceMaterialDetailId () );
            double sumNum = 0;
            if ( ! CollectionUtils.isEmpty ( decisionList ) ) {
                sumNum = decisionList.stream ().mapToDouble ( materialDecision -> Double.parseDouble ( materialDecision.getNum () ) ).sum ();
            }
            //获取已经下推的采购入库单数量
            List<KingInventoryMaterialEntity> inventoryMaterials = kingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ()
                    .ne ( KingInventoryMaterialEntity :: getInventoryId, inventoryMaterial.getInventoryId () ).eq ( KingInventoryMaterialEntity :: getRelationId, inventoryMaterial.getRelationId () )
                    .eq ( KingInventoryMaterialEntity :: getSourceMaterialDetailId, inventoryMaterial.getSourceMaterialDetailId () ) );
            double sumReceiptsNum = 0;
            if ( ! CollectionUtils.isEmpty ( inventoryMaterials ) ) {
                sumReceiptsNum = inventoryMaterials.stream ().mapToDouble ( hasInventoryMaterial -> Double.parseDouble ( hasInventoryMaterial.getReceiptsNum () ) ).sum ();
            }
            //剩余可推数量
            double surplusNum = sumNum - sumReceiptsNum;
            //判断本次下推数量是否满足
            if ( Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) > surplusNum ) {
                throw new CustomException ( "下推数量不能超过收料通知单可下推数量！" );
            }
            //todo 平账(此处计算的是收料通知单下推检验单并且检验单已经检验合格的数量)
        }
        return inventoryMaterial;
    }

    /**
     * 根据收料通知单id和物料明细查询检验合格以及让步接收的数量
     *
     * @param receiveNoticeId
     * @param materialId
     * @return
     */
    private List<KingCheckMaterialUseDecisionEntity> queryCheckMaterialByReceiveNotice ( String receiveNoticeId, String materialId ) {
        List<KingCheckMaterialUseDecisionEntity> decisionList = checkMaterialUseDecisionService.list (
                new LambdaQueryWrapper<KingCheckMaterialUseDecisionEntity> ().eq ( KingCheckMaterialUseDecisionEntity :: getRelationId, receiveNoticeId )
                        .eq ( KingCheckMaterialUseDecisionEntity :: getSourceMaterialDetailId, materialId )
                        .and ( wrapper -> wrapper.in ( KingCheckMaterialUseDecisionEntity :: getUseDecision, ConstUtil.CHECK_DECISION_ACCEPT, ConstUtil.CHECK_DECISION_CONCESSION_ACCEPT ) ) );
        return decisionList;
    }

    /**
     * 保存采购入库单物料明细
     *
     * @param kingInventory
     * @param materialLists
     */
    private void saveMaterialAndDetail ( KingInventoryEntity kingInventory, List<KingInventoryMaterialEntity> materialLists, String message ) {
        materialLists.forEach ( inventoryMaterial -> {
            String inventoryMaterialId = SnowflakeIdWorker.getInstance ().nextStringId ();
            inventoryMaterial.setId ( inventoryMaterialId );
            inventoryMaterial.setInventoryId ( kingInventory.getId () );
            inventoryMaterial.setUserId ( kingInventory.getUserId () );
            inventoryMaterial.setCreateTime ( kingInventory.getCreateTime () );
            boolean inventoryMaterialFlag = kingInventoryMaterialService.save ( inventoryMaterial );
            if ( ! inventoryMaterialFlag ) {
                throw new CustomException ( message + "物料明细失败！" );
            }
            if ( Objects.nonNull ( inventoryMaterial.getMaterialDetail () ) ) {
                KingInventoryMaterialDetailEntity materialDetail = inventoryMaterial.getMaterialDetail ();
                String materialDetailId = SnowflakeIdWorker.getInstance ().nextStringId ();
                materialDetail.setId ( materialDetailId );
                materialDetail.setInventoryId ( kingInventory.getId () );
                materialDetail.setInventoryMaterialId ( inventoryMaterialId );
                materialDetail.setUserId ( kingInventory.getUserId () );
                materialDetail.setCreateTime ( kingInventory.getCreateTime () );
                boolean inventoryMaterialDetailFlag = kingInventoryMaterialDetailService.save ( materialDetail );
                if ( ! inventoryMaterialDetailFlag ) {
                    throw new CustomException ( message + "物料明细信息失败！" );
                }
                if ( ! CollectionUtils.isEmpty ( materialDetail.getMaterialDetailSerials () ) ) {
                    List<KingInventoryMaterialDetailSerialEntity> materialDetailSerials = materialDetail.getMaterialDetailSerials ();
                    for ( KingInventoryMaterialDetailSerialEntity materialDetailSerial : materialDetailSerials ) {
                        materialDetailSerial.setId ( SnowflakeIdWorker.getInstance ().nextStringId () );
                        materialDetailSerial.setInventoryId ( kingInventory.getId () );
                        materialDetailSerial.setInventoryMaterialId ( inventoryMaterialId );
                        materialDetailSerial.setMaterialDetailId ( materialDetailId );
                        materialDetailSerial.setUserId ( kingInventory.getUserId () );
                        materialDetailSerial.setCreateTime ( kingInventory.getCreateTime () );
                        kingInventoryMaterialDetailSerialService.save ( materialDetailSerial );
                    }
                }
            }
        } );
    }

    /**
     * 提交销售出库单检验
     *
     * @param kingInventory
     * @return
     */

    private AjaxResult saveSaleKingInventory ( KingInventoryEntity kingInventory ) {
        if ( StringUtils.isBlank ( kingInventory.getId () ) ) {
            return AjaxResult.error ( "请先暂存该单据！" );
        }
        if ( Objects.isNull ( kingInventory.getModelId () ) ) {
            return AjaxResult.error ( "审批流程modelId不能为空！" );
        }
        if ( CollectionUtils.isEmpty ( kingInventory.getMaterialLists () ) ) {
            return AjaxResult.error ( "物料明细不能为空！" );
        }
        List<KingInventoryMaterialEntity> materialLists = kingInventory.getMaterialLists ();
        List<String> orderIdList = materialLists.stream ().filter ( Objects :: nonNull ).distinct ().map ( KingInventoryMaterialEntity :: getRelationId ).collect ( Collectors.toList () );
        List<SaleOrderEntity> list = saleOrderService.list ( new QueryWrapper<SaleOrderEntity> ().in ( "id", orderIdList ) );
        List<String> saleGroupList = list.stream ().filter ( Objects :: nonNull ).distinct ().map ( SaleOrderEntity :: getSaleGroup ).collect ( Collectors.toList () );
        if ( ! saleGroupList.isEmpty () && saleGroupList.size () > 1 ) {
            return AjaxResult.error ( "所选单据销售组不一致，无法操作！" );
        }
        List<String> customerList = list.stream ().filter ( Objects :: nonNull ).distinct ().map ( SaleOrderEntity :: getCustomerId ).collect ( Collectors.toList () );
        if ( ! customerList.isEmpty () && customerList.size () > 1 ) {
            return AjaxResult.error ( "所选单据客户不一致，无法操作！" );
        }
        List<String> saleIdList = list.stream ().filter ( Objects :: nonNull ).distinct ().map ( SaleOrderEntity :: getSaleId ).collect ( Collectors.toList () );
        if ( ! saleIdList.isEmpty () && saleIdList.size () > 1 ) {
            return AjaxResult.error ( "所选单据销售员不一致，无法操作！" );
        }
        List<String> currencyList = list.stream ().filter ( Objects :: nonNull ).distinct ().map ( SaleOrderEntity :: getCurrency ).collect ( Collectors.toList () );
        if ( ! currencyList.isEmpty () && currencyList.size () > 1 ) {
            return AjaxResult.error ( "所选单据币别不一致，无法操作！" );
        }
        checkSaleMaterialNumAndAmount ( materialLists );
        //先删除暂存时保存的物料明细信息
        removeMaterialAndDetail ( kingInventory.getId () );
        saveMaterialAndDetail ( kingInventory, materialLists, "提交销售出库单" );
        //启动审批流程
        StartProcessDto startDto = new StartProcessDto ().setBusinessId ( kingInventory.getId () ).setBusinessType ( kingInventory.getBusinessType () ).setModelId ( kingInventory.getModelId () );
        startDto.setBusinessName ( "销售出库单_".concat ( kingInventory.getId () ) );
        String instanceId = actModelService.startProcess ( startDto );
        //销售出库单单号生成
        if ( StringUtils.isEmpty ( kingInventory.getDocCode () ) ) {
            String companyId = CurrentUserUtil.getCompanyId ();
            SysDept sysDept = sysDeptService.getById ( companyId );
            int count = this.count ( new LambdaQueryWrapper<KingInventoryEntity> ().eq ( KingInventoryEntity :: getType, ConstUtil.KING_INVENTORY_TYPE_OUT ) );
            String countStr = String.format ( "%06d", count );
            String firstLetter = ChineseToPinyin.getFirstLetter ( sysDept.getDeptName () );
            String docCode = firstLetter.concat ( "_XSCK_" ).concat ( countStr );
            kingInventory.setDocCode ( docCode );
        }
        kingInventory.setState ( ConstUtil.STATE_IN_PROCESS ).setInstanceId ( instanceId );
        boolean updated = this.updateById ( kingInventory );
        if ( ! updated ) {
            return AjaxResult.error ( "提交销售出库单失败!" );
        }
        return AjaxResult.success ( "提交销售出库单成功!" );
    }


    @Override
    public AjaxResult saleDraftKingInventory ( KingInventoryEntity kingInventory ) {
        boolean saveFlag = false;
        //计算总表三个金额
        List<KingInventoryMaterialEntity> materialLists = kingInventory.getMaterialLists ();
        double taxAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTaxAmount () ) ? "0" : detail.getTaxAmount () ) ).sum ();
        double moneyAmount = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getMoneyAmount () ) ? "0" : detail.getMoneyAmount () ) ).sum ();
        double totalTaxPrice = materialLists.stream ().mapToDouble ( detail -> Double.parseDouble ( StringUtils.isBlank ( detail.getTotalTaxPrice () ) ? "0" : detail.getTotalTaxPrice () ) ).sum ();
        kingInventory.setTaxAmount ( String.valueOf ( taxAmount ) );
        kingInventory.setMoneyAmount ( String.valueOf ( moneyAmount ) );
        kingInventory.setTotalPriceTax ( String.valueOf ( totalTaxPrice ) );
        if ( StringUtils.isEmpty ( kingInventory.getId () ) ) {
            String inventoryId = SnowflakeIdWorker.getInstance ().nextStringId ();
            Date nowDate = DateUtils.getNowDate ();
            String userId = SecurityUtils.getLoginUser ().getUser ().getUserId ();
            kingInventory.setId ( inventoryId ).setCreateTime ( nowDate ).setUserId ( userId );
            if ( ! CollectionUtils.isEmpty ( kingInventory.getMaterialLists () ) ) {
                this.saveMaterialAndDetail ( kingInventory, kingInventory.getMaterialLists (), "暂存销售出库单" );
            }
            //流程状态：暂存
            kingInventory.setState ( ConstUtil.STATE_IN_DRAFT );
            kingInventory.setType ( ConstUtil.KING_INVENTORY_TYPE_OUT );
            if ( StringUtils.isEmpty ( kingInventory.getDocCode () ) ) {
                String companyId = CurrentUserUtil.getCompanyId ();
                SysDept sysDept = sysDeptService.getById ( companyId );
                int count = this.count ( new LambdaQueryWrapper<KingInventoryEntity> ().eq ( KingInventoryEntity :: getType, ConstUtil.KING_INVENTORY_TYPE_OUT ) );
                String countStr = String.format ( "%06d", count );
                String firstLetter = ChineseToPinyin.getFirstLetter ( sysDept.getDeptName () );
                String docCode = firstLetter.concat ( "_XSCK_" ).concat ( countStr );
                kingInventory.setDocCode ( docCode );
            }
            saveFlag = this.save ( kingInventory );
        } else {
            //先删除暂存时保存的物料明细信息
            removeMaterialAndDetail ( kingInventory.getId () );
            if ( ! CollectionUtils.isEmpty ( kingInventory.getMaterialLists () ) ) {
                this.saveMaterialAndDetail ( kingInventory, kingInventory.getMaterialLists (), "暂存销售出库单" );
            }
            saveFlag = this.updateById ( kingInventory );
        }

        if ( saveFlag ) {
            return AjaxResult.success ( "暂存销售出库单成功！", kingInventory.getId () );
        }
        return AjaxResult.error ( "暂存销售出库单失败！" );
    }


    @Override
    @Transactional ( rollbackFor = Exception.class )
    public AjaxResult saleSubmitKingInventory ( KingInventoryEntity kingInventory ) {
        AjaxResult ajaxResult = this.saveSaleKingInventory ( kingInventory );
        return ajaxResult;
    }

    /**
     * 金蝶销售出库单审批通过更新即时库存
     *
     * @param kingInventoryEntity
     * @return
     */
    @Override
    @Transactional ( rollbackFor = Exception.class )
    public boolean approvedSaleKingInventory ( KingInventoryEntity kingInventoryEntity ) {
        List<KingInventoryMaterialEntity> list = kingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().eq ( KingInventoryMaterialEntity :: getInventoryId, kingInventoryEntity.getId () ) );
        list.forEach ( s -> {
            //实际出入库数量
            BigDecimal purchaseNum = new BigDecimal ( s.getReceiptsNum () );
            //判断puurchaseNum是否大于0
            if ( purchaseNum.compareTo ( BigDecimal.ZERO ) > 0 ) {
                //查询该物料的库存数量
                KingRealInventoryEntity realInventoryEntity = kingRealInventoryService.getOne ( new LambdaQueryWrapper<KingRealInventoryEntity> ()
                                                                                                        .eq ( KingRealInventoryEntity :: getMaterialCode, s.getMaterialCode () )
                                                                                                        .eq ( KingRealInventoryEntity :: getWarehouseCode, s.getWarehouseCode () )
                                                                                                        .eq ( KingRealInventoryEntity :: getWarehousePosition, s.getWarehousePosition () )
                );
                if ( Objects.nonNull ( realInventoryEntity ) ) {//如果此物料存在
                    if ( ConstUtil.KING_INVENTORY_TYPE_IN.equals ( kingInventoryEntity.getType () ) ) {
                        if ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).compareTo ( BigDecimal.ZERO ) > 0 ) {
                            realInventoryEntity.setInventoryNum ( String.valueOf ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).add ( purchaseNum ) ) );
                        } else {
                            realInventoryEntity.setInventoryNum ( String.valueOf ( purchaseNum ) );
                        }
                    } else {
                        //判断库存数量如果大于purchaseNum，现在库存数量等于之前库存数量减去purchaseNum
                        if ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).compareTo ( BigDecimal.ZERO ) == 0 ) {
                            throw new RuntimeException ( "库存数量不足，无法操作！" );
                        }
                        if ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).compareTo ( purchaseNum ) < 0 ) {
                            throw new RuntimeException ( "库存数量不足，无法操作！" );
                        }
                        if ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).compareTo ( purchaseNum ) >= 0 ) {
                            realInventoryEntity.setInventoryNum ( String.valueOf ( new BigDecimal ( realInventoryEntity.getInventoryNum () ).subtract ( purchaseNum ) ) );
                        }
                    }
                    kingRealInventoryService.updateById ( realInventoryEntity );
                } else {//刚入库得新建
                    KingRealInventoryEntity kingRealInventoryEntity = new KingRealInventoryEntity ();
                    kingRealInventoryEntity.setId ( SnowflakeIdWorker.getInstance ().nextStringId () );
                    kingRealInventoryEntity.setMaterialCode ( s.getMaterialCode () );
                    kingRealInventoryEntity.setInventoryNum ( String.valueOf ( s.getPurchaseNum () ) );
                    kingRealInventoryEntity.setMeteringUnitName ( s.getInventoryUnit () );
                    kingRealInventoryEntity.setWarehouseCode ( s.getWarehouseCode () );
                    kingRealInventoryEntity.setWarehousePosition ( s.getWarehousePosition () );
                    kingRealInventoryEntity.setCreateTime ( DateUtils.getNowDate () );
                    kingRealInventoryService.save ( kingRealInventoryEntity );
                }
            }
        } );
        //调用应收应付处理后续业务
        KingInventoryEntity inventoryEntity = this.getById ( kingInventoryEntity );
        if ( "0".equals ( inventoryEntity.getType () ) ) {
            //采购入库，拿源单是采购订单的调用应付单业务处理
            List<KingInventoryMaterialEntity> collect = list.stream ().filter ( detail -> "0".equals ( detail.getSourceType () ) && StringUtils.isNotBlank ( detail.getRelationId () ) ).collect ( Collectors.toList () );
            if ( collect.size () > 0 ) {
                List<String> orderIds = collect.stream ().map ( KingInventoryMaterialEntity :: getRelationId ).distinct ().collect ( Collectors.toList () );
                orderIds.forEach ( orderId -> {
                    iKingInvoicePayableService.inventoryApprove ( kingInventoryEntity.getId (), orderId );
                } );
            }
        } else if ( "1".equals ( inventoryEntity.getType () ) ) {
            //销售出库，拿源单是销售订单的时候调用应收单业务处理
            List<KingInventoryMaterialEntity> collect = list.stream ().filter ( detail -> ("2".equals ( detail.getSourceType ()) && StringUtils.isNotBlank ( detail.getRelationId () ) ) ).collect ( Collectors.toList () );
            if ( collect.size () > 0 ) {
                List<String> orderIds = collect.stream ().map ( KingInventoryMaterialEntity :: getRelationId ).distinct ().collect ( Collectors.toList () );
                orderIds.forEach ( orderId -> {
                    iKingInvoiceReceivableService.inventoryApprove ( kingInventoryEntity.getId (), orderId );
                } );
            }
        }
        return this.updateById ( kingInventoryEntity );
    }

    /**
     * 校验销售订单物料数量和金额
     *
     * @param materialLists
     */

    private void checkSaleMaterialNumAndAmount ( List<KingInventoryMaterialEntity> materialLists ) {
        materialLists.forEach ( inventoryMaterial -> {
            if ( StringUtils.isNotEmpty ( inventoryMaterial.getSourceMaterialDetailId () ) ) {
                //销售订单明细的数量和金额
                MaterialDetailEntity saleMaterialDetailOne = materialDetailService.getById ( inventoryMaterial.getSourceMaterialDetailId () );
                double orderNumber = Double.parseDouble ( saleMaterialDetailOne.getNumber () );
                BigDecimal orderAmountMoney = new BigDecimal ( saleMaterialDetailOne.getAmountMoney () );
                //该物料明细已经形成销售出库单的数量和金额
                List<KingInventoryMaterialEntity> inventoryMaterials = kingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ()
                        .eq ( KingInventoryMaterialEntity :: getRelationId, inventoryMaterial.getRelationId () )
                        .eq ( KingInventoryMaterialEntity :: getSourceMaterialDetailId, inventoryMaterial.getSourceMaterialDetailId () )
                        .eq(KingInventoryMaterialEntity::getIsUsed,ConstUtil.IS_USED_YES)
                );
                double sumReceiptsNum = 0;
                BigDecimal totalMoneyAmount = BigDecimal.ZERO;
                if ( ! CollectionUtils.isEmpty ( inventoryMaterials ) ) {
                    //计算该物料已经出库的数量总和
                    sumReceiptsNum = inventoryMaterials.stream ().mapToDouble ( material -> Double.parseDouble ( material.getReceiptsNum () ) ).sum ();
                    //计算该物料已经出库的总金额
                    totalMoneyAmount = inventoryMaterials.stream()
                            .map(KingInventoryMaterialEntity::getMoneyAmount)
                            .map(amount -> amount == null ? BigDecimal.ZERO : new BigDecimal(amount))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                //剩余可引用数量
                double surplusNum = orderNumber - sumReceiptsNum;
                if ( Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) > surplusNum ) {
                    throw new RuntimeException ( "引用数量不能超过销售订单数量！" );
                }

                BigDecimal surplusAmountMoney = orderAmountMoney.subtract ( totalMoneyAmount );
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getMoneyAmount () ) ) {
                    int comparisonResult = new BigDecimal(inventoryMaterial.getMoneyAmount ()).compareTo(surplusAmountMoney);
                    if(comparisonResult > 0){
                        throw new CustomException ( "引用金额不能超过销售订单金额！" );
                    }
                }
                //平账
                if ( Double.parseDouble ( inventoryMaterial.getReceiptsNum () ) == surplusNum ) {
                    //销售订单该物料明细的价税合计
                    String orderTotalTaxPrice = saleMaterialDetailOne.getTotalTaxPrice ();
                    //该物料明细已经形成采购入库单的价税合计
                    List<String> inventoryMaterialIdList = inventoryMaterials.stream ().filter ( Objects :: nonNull ).distinct ().map ( KingInventoryMaterialEntity :: getId ).collect ( Collectors.toList () );
                    List<KingInventoryMaterialDetailEntity> inventoryMaterialDetailList = kingInventoryMaterialDetailService.list ( new QueryWrapper<KingInventoryMaterialDetailEntity> ()
                            .in ( "inventory_material_id", inventoryMaterialIdList ) );
                    BigDecimal inventoryMaterialDetailTotalTaxPrice = inventoryMaterialDetailList.stream ().filter ( Objects :: nonNull ).map ( materialDetail -> new BigDecimal ( materialDetail.getTotalTaxPrice () ) ).reduce ( BigDecimal.ZERO, BigDecimal :: add );
                    //计算剩余的价税合计(该物料明细的价税合计 ➖ 已经形成销售出库单的价税合计)
                    BigDecimal surplusTotalTaxPrice = new BigDecimal ( orderTotalTaxPrice ).subtract ( inventoryMaterialDetailTotalTaxPrice );
                    //计算单价(剩余的价税合计 / 此次数量)
                    BigDecimal price = surplusTotalTaxPrice.divide ( new BigDecimal ( inventoryMaterial.getReceiptsNum () ), BigDecimal.ROUND_HALF_UP );
                    //将值赋值给原字段
                    inventoryMaterial.getMaterialDetail ().setPrice ( String.valueOf ( price ) );
                    inventoryMaterial.getMaterialDetail ().setTotalTaxPrice ( String.valueOf ( surplusTotalTaxPrice ) );
                }
            }
        } );
    }


    /**
     * 查询金蝶-入库/出库单
     *
     * @param id 金蝶-入库/出库单ID
     * @return 金蝶-入库/出库单
     */
    @Override
    public KingInventoryEntity selectKingInventoryEntityById ( String id ) {
        KingInventoryEntity kingInventory = kingInventoryMapper.selectKingInventoryEntityById ( id );
        if ( Objects.nonNull ( kingInventory ) ) {
            //收料组织
            SysDept receiveOrg = sysDeptService.getOne ( new LambdaQueryWrapper<SysDept> ().eq ( SysDept :: getDeptCode, kingInventory.getReceivingOrg () ) );
            Optional.ofNullable ( receiveOrg ).ifPresent ( r -> {
                kingInventory.setReceivingOrgName ( r.getDeptName () );
            } );
            //采购组织
            SysDept purchaseOrg = sysDeptService.getOne ( new LambdaQueryWrapper<SysDept> ().eq ( SysDept :: getDeptCode, kingInventory.getPurchaseOrg () ) );
            Optional.ofNullable ( purchaseOrg ).ifPresent ( r -> {
                kingInventory.setPurchaseOrgName ( r.getDeptName () );
            } );
            //收料部门
            SysDept receiveDept = sysDeptService.getOne ( new LambdaQueryWrapper<SysDept> ().eq ( SysDept :: getDeptCode, kingInventory.getReceivingDept () ) );
            Optional.ofNullable ( receiveDept ).ifPresent ( r -> {
                kingInventory.setReceivingDeptName ( r.getDeptName () );
            } );
            //采购部门
            SysDept purchaseDept = sysDeptService.getOne ( new LambdaQueryWrapper<SysDept> ().eq ( SysDept :: getDeptCode, kingInventory.getPurchaseDept () ) );
            Optional.ofNullable ( purchaseDept ).ifPresent ( r -> {
                kingInventory.setPurchaseDeptName ( r.getDeptName () );
            } );
            //库存组
            if ( StringUtils.isNotEmpty ( kingInventory.getInventoryGroup () ) ) {
                KingBaseBusinessGroupDetailEntity inventoryGroupDetail = kingBaseBusinessGroupDetailService.getOne ( new LambdaQueryWrapper<KingBaseBusinessGroupDetailEntity> ().eq ( KingBaseBusinessGroupDetailEntity :: getBusinessCode, kingInventory.getInventoryGroup () ) );
                Optional.ofNullable ( inventoryGroupDetail ).ifPresent ( b -> {
                    kingInventory.setInventoryGroupName ( b.getBusinessName () );
                } );
            }
            //采购组
            if ( StringUtils.isNotEmpty ( kingInventory.getPurchaseGroup () ) ) {
                KingBaseBusinessGroupDetailEntity purchaseGroupDetail = kingBaseBusinessGroupDetailService.getOne ( new LambdaQueryWrapper<KingBaseBusinessGroupDetailEntity> ().eq ( KingBaseBusinessGroupDetailEntity :: getBusinessCode, kingInventory.getPurchaseGroup () ) );
                Optional.ofNullable ( purchaseGroupDetail ).ifPresent ( b -> {
                    kingInventory.setPurchaseGroupName ( b.getBusinessName () );
                } );
            }
            //仓管员
            SysUser managementBy = sysUserService.getOne ( new LambdaQueryWrapper<SysUser> ().eq ( SysUser :: getUserCode, kingInventory.getManagementBy () ) );
            Optional.ofNullable ( managementBy ).ifPresent ( m -> {
                kingInventory.setManagementByName ( m.getUserName () );
            } );
            //采购员
            SysUser purchaseBy = sysUserService.getOne ( new LambdaQueryWrapper<SysUser> ().eq ( SysUser :: getUserCode, kingInventory.getPurchaseBy () ) );
            Optional.ofNullable ( purchaseBy ).ifPresent ( p -> {
                kingInventory.setPurchaseByName ( p.getUserName () );
            } );
            //供应商
            SupplierEntity supplierEntity = supplierService.getById ( kingInventory.getSupplierId () );
            Optional.ofNullable ( supplierEntity ).ifPresent ( p -> {
                kingInventory.setSupplierName ( p.getSupplierName () );
            } );
            //需求组织
            SysDept requireDept = sysDeptService.getOne ( new LambdaQueryWrapper<SysDept> ().eq ( SysDept :: getDeptCode, kingInventory.getRequireDept () ) );
            Optional.ofNullable ( requireDept ).ifPresent ( r -> {
                kingInventory.setRequireDeptName ( r.getDeptName () );
            } );
            //供货方名称
            SupplierEntity providerName = supplierService.getById ( kingInventory.getProviderId () );
            Optional.ofNullable ( providerName ).ifPresent ( p -> {
                kingInventory.setProviderName ( p.getSupplierName () );
            } );
            //供货方联系人名称
            KingBaseContactsEntity baseContactsEntity = baseContactsService.getOne(new LambdaQueryWrapper<KingBaseContactsEntity>().eq(KingBaseContactsEntity::getContactsCode, kingInventory.getProviderContacts()));
            Optional.ofNullable(baseContactsEntity).ifPresent(b -> {
                kingInventory.setProviderContactsName(b.getName());
            });
            //结算方名称
            SupplierEntity balanceName = supplierService.getById ( kingInventory.getBalanceId () );
            Optional.ofNullable ( balanceName ).ifPresent ( b -> {
                kingInventory.setBalanceName ( b.getSupplierName () );
            } );
            //收款方名称
            SupplierEntity receiveName = supplierService.getById ( kingInventory.getReceiveId () );
            Optional.ofNullable ( receiveName ).ifPresent ( r -> {
                kingInventory.setReceiveName ( r.getSupplierName () );
            } );
            //结算组织名称
            SysDept settlementOrg = sysDeptService.getById ( kingInventory.getSettlementOrg () );
            Optional.ofNullable ( settlementOrg ).ifPresent ( s -> {
                kingInventory.setSettlementOrgName ( s.getDeptName () );
            } );
            //结算方式名称
            KingBaseSettlementTypeEntity kingBaseSettlementType = kingBaseSettlementTypeService.getOne ( new LambdaQueryWrapper<KingBaseSettlementTypeEntity> ().eq ( KingBaseSettlementTypeEntity :: getBizCode, kingInventory.getSettlementMethod () ) );
            Optional.ofNullable ( kingBaseSettlementType ).ifPresent ( k -> {
                kingInventory.setSettlementMethodName ( k.getTitle () );
            } );
            //价目表名称
            KingPurchasePriceEntity purchasePriceEntity = kingPurchasePriceService.getOne ( new LambdaQueryWrapper<KingPurchasePriceEntity> ().eq ( KingPurchasePriceEntity :: getCode, kingInventory.getPriceInfoCode () ) );
            Optional.ofNullable ( purchasePriceEntity ).ifPresent ( p -> {
                kingInventory.setPriceInfoName ( p.getName () );
            } );
            //汇率类型
            if ( StringUtils.isNotEmpty ( kingInventory.getExchangeRateType () ) ) {
                KingBaseExchangeRateTypeEntity exchangeRateType = kingBaseExchangeRateTypeService.getOne ( new LambdaQueryWrapper<KingBaseExchangeRateTypeEntity> ().eq ( KingBaseExchangeRateTypeEntity :: getCode, kingInventory.getExchangeRateType () ) );
                Optional.ofNullable ( exchangeRateType ).ifPresent ( e -> {
                    kingInventory.setExchangeRateTypeName ( e.getName () );
                } );
            }
            //结算币别
            KingBaseCurrencyEntity KingBaseCurrency = kingBaseCurrencyService.getOne ( new LambdaQueryWrapper<KingBaseCurrencyEntity> ().eq ( KingBaseCurrencyEntity :: getCode, kingInventory.getSettlementCurrency () ) );
            Optional.ofNullable ( KingBaseCurrency ).ifPresent ( k -> {
                kingInventory.setSettlementCurrencyName ( k.getCurrencyName () );
            } );
            //折扣表名称
            KingPurchasePriceEntity discountInfo = kingPurchasePriceService.getOne ( new LambdaQueryWrapper<KingPurchasePriceEntity> ().eq ( KingPurchasePriceEntity :: getCode, kingInventory.getDiscountInfoCode () ) );
            Optional.ofNullable ( discountInfo ).ifPresent ( d -> {
                kingInventory.setDiscountInfoName ( d.getName () );
            } );
            //付款条件名称
            KingBaseReceiptPayConditionEntity receiptPayCondition = kingBaseReceiptPayConditionService.getOne ( new LambdaQueryWrapper<KingBaseReceiptPayConditionEntity> ().eq ( KingBaseReceiptPayConditionEntity :: getConditionCode, kingInventory.getTermOfPayment () ) );
            Optional.ofNullable ( receiptPayCondition ).ifPresent ( r -> {
                kingInventory.setTermOfPaymentName ( r.getTitle () );
            } );
            List<KingInventoryMaterialEntity> inventoryMaterials = kingInventoryMaterialService.list ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().eq ( KingInventoryMaterialEntity :: getInventoryId, kingInventory.getId () ) );
            inventoryMaterials.stream ().filter ( Objects :: nonNull ).forEach ( inventoryMaterial -> {
                //源单处理
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getSourceType () ) ) {
                    if ( inventoryMaterial.getSourceType ().equals ( ConstUtil.INVENTORY_SOURCE_TYPE_ORDER ) ) {
                        inventoryMaterial.setOrderId ( inventoryMaterial.getRelationId () );
                        inventoryMaterial.setOrderNumber ( inventoryMaterial.getRelationCode () );
                    }
                    if ( inventoryMaterial.getSourceType ().equals ( ConstUtil.INVENTORY_SOURCE_TYPE_RECEIVE_NOTICE ) ) {
                        KingReceiveNoticeMaterialEntity receiveNoticeMaterial = kingReceiveNoticeMaterialService.getById ( inventoryMaterial.getSourceMaterialDetailId () );
                        if ( Objects.nonNull ( receiveNoticeMaterial ) ) {
                            inventoryMaterial.setOrderId ( receiveNoticeMaterial.getRelationId () );
                            inventoryMaterial.setOrderNumber ( receiveNoticeMaterial.getRelationCode () );
                        }
                    }
                }
                //库存状态名称
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getInventoryStatus () ) ) {
                    KingBaseInventoryStatusEntity inventoryStatus = kingBaseInventoryStatusService.getOne ( new LambdaQueryWrapper<KingBaseInventoryStatusEntity> ().eq ( KingBaseInventoryStatusEntity :: getInventoryStatusCode, inventoryMaterial.getInventoryStatus () ) );
                    if ( Objects.nonNull ( inventoryStatus ) ) {
                        inventoryMaterial.setInventoryStatusName ( inventoryStatus.getInventoryStatusName () );
                    }
                }
                //计价单位
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getPricingUnit () ) ) {
                    KingBaseMeteringUnitEntity pricingUnit = meteringUnitService.getOne ( new LambdaQueryWrapper<KingBaseMeteringUnitEntity> ().eq ( KingBaseMeteringUnitEntity :: getMeteringUnitCode, inventoryMaterial.getPricingUnit () ) );
                    Optional.ofNullable ( pricingUnit ).ifPresent ( p -> {
                        inventoryMaterial.setPricingUnitName ( p.getMeteringUnitName () );
                    } );
                }
                //采购单位
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getPurchaseUnit () ) ) {
                    KingBaseMeteringUnitEntity purchaseUnit = meteringUnitService.getOne ( new LambdaQueryWrapper<KingBaseMeteringUnitEntity> ().eq ( KingBaseMeteringUnitEntity :: getMeteringUnitCode, inventoryMaterial.getPurchaseUnit () ) );
                    Optional.ofNullable ( purchaseUnit ).ifPresent ( p -> {
                        inventoryMaterial.setPurchaseUnitName ( p.getMeteringUnitName () );
                    } );
                }
                //库存单位
                if ( StringUtils.isNotEmpty ( inventoryMaterial.getInventoryUnit () ) ) {
                    KingBaseMeteringUnitEntity inventoryUnit = meteringUnitService.getOne ( new LambdaQueryWrapper<KingBaseMeteringUnitEntity> ().eq ( KingBaseMeteringUnitEntity :: getMeteringUnitCode, inventoryMaterial.getInventoryUnit () ) );
                    Optional.ofNullable ( inventoryUnit ).ifPresent ( i -> {
                        inventoryMaterial.setInventoryUnitName ( i.getMeteringUnitName () );
                    } );
                }
                //仓库名称
                if(!StringUtils.isEmpty(inventoryMaterial.getWarehouseCode())){
                    WarehouseEntity warehouseEntity = warehouseService.getOne(new LambdaQueryWrapper<WarehouseEntity>().eq(WarehouseEntity::getWareCode, inventoryMaterial.getWarehouseCode()));
                    Optional.ofNullable(warehouseEntity).ifPresent(warehouse -> {
                        inventoryMaterial.setWarehouseName(warehouse.getWareName());
                    });
                }
                KingInventoryMaterialDetailEntity kingInventoryMaterialDetail = kingInventoryMaterialDetailService.getOne ( new LambdaQueryWrapper<KingInventoryMaterialDetailEntity> ().eq ( KingInventoryMaterialDetailEntity :: getInventoryId, kingInventory.getId () ).eq ( KingInventoryMaterialDetailEntity :: getInventoryMaterialId, inventoryMaterial.getId () ) );
                if ( Objects.nonNull ( kingInventoryMaterialDetail ) ) {
                    List<KingInventoryMaterialDetailSerialEntity> materialDetailSerials = kingInventoryMaterialDetailSerialService.list ( new LambdaQueryWrapper<KingInventoryMaterialDetailSerialEntity> ()
                            .eq ( KingInventoryMaterialDetailSerialEntity :: getInventoryId, kingInventory.getId () ).eq ( KingInventoryMaterialDetailSerialEntity :: getInventoryMaterialId, inventoryMaterial.getId () ).eq ( KingInventoryMaterialDetailSerialEntity :: getMaterialDetailId, kingInventoryMaterialDetail.getId () ) );
                    kingInventoryMaterialDetail.setMaterialDetailSerials ( materialDetailSerials );
                }
                inventoryMaterial.setMaterialDetail ( kingInventoryMaterialDetail );
            } );
            kingInventory.setMaterialLists ( inventoryMaterials );
        }
        return kingInventory;
    }

    /**
     * 查询金蝶-入库/出库单列表
     *
     * @param kingInventoryEntity 金蝶-入库/出库单
     * @return 金蝶-入库/出库单
     */
    @Override
    public List<KingInventoryEntity> selectKingInventoryEntityList ( KingInventoryEntity kingInventoryEntity ) {
        return kingInventoryMapper.selectKingInventoryEntityList ( kingInventoryEntity );
    }

    /**
     * 新增金蝶-入库/出库单
     *
     * @param kingInventoryEntity 金蝶-入库/出库单
     * @return 结果
     * 逻辑：
     * 数量和金额都不能超采购订单；
     * 供应商、币别、采购组织不同不得合并下推；
     */
    @Override
    public int insertKingInventoryEntity ( KingInventoryEntity kingInventoryEntity ) {
        kingInventoryEntity.setCreateTime ( DateUtils.getNowDate () );
        return kingInventoryMapper.insertKingInventoryEntity ( kingInventoryEntity );
    }


    /**
     * 修改金蝶-入库/出库单
     *
     * @param kingInventoryEntity 金蝶-入库/出库单
     * @return 结果
     */
    @Override
    public int updateKingInventoryEntity ( KingInventoryEntity kingInventoryEntity ) {
        return kingInventoryMapper.updateKingInventoryEntity ( kingInventoryEntity );
    }

    /**
     * 封装公用的删除方法
     *
     * @param id
     */
    private void removeMaterialAndDetail ( String id ) {
        kingInventoryMaterialService.remove ( new LambdaQueryWrapper<KingInventoryMaterialEntity> ().eq ( KingInventoryMaterialEntity :: getInventoryId, id ) );
        kingInventoryMaterialDetailService.remove ( new LambdaQueryWrapper<KingInventoryMaterialDetailEntity> ().eq ( KingInventoryMaterialDetailEntity :: getInventoryId, id ) );
        kingInventoryMaterialDetailSerialService.remove ( new LambdaQueryWrapper<KingInventoryMaterialDetailSerialEntity> ().eq ( KingInventoryMaterialDetailSerialEntity :: getInventoryId, id ) );
    }

    /**
     * 批量删除金蝶-入库/出库单
     *
     * @param ids 需要删除的金蝶-入库/出库单ID
     * @return 结果
     */
    @Override
    public int deleteKingInventoryEntityByIds ( String[] ids ) {
        for ( String id : ids ) {
            removeMaterialAndDetail ( id );
        }
        return kingInventoryMapper.deleteKingInventoryEntityByIds ( ids );
    }

    /**
     * 删除金蝶-入库/出库单信息
     *
     * @param id 金蝶-入库/出库单ID
     * @return 结果
     */
    @Override
    public int deleteKingInventoryEntityById ( String id ) {
        removeMaterialAndDetail ( id );
        return kingInventoryMapper.deleteKingInventoryEntityById ( id );
    }

    public AjaxResult getMenuSaleInventoryList ( KingInventoryEntity kingInventoryEntity ) {
        kingInventoryEntity.setPage ( ( kingInventoryEntity.getPage () - 1 ) * kingInventoryEntity.getLimit () );
        PageParam page = new PageParam ();
        List<MenuKingInventoryMaterialVo> menuKingInventoryMaterialVoIPage = kingInventoryMapper.selectMenuSaleInventoryList ( kingInventoryEntity );
        page.setRecords ( menuKingInventoryMaterialVoIPage ).setTotal ( kingInventoryMapper.selectMenuSaleInventoryCount ( kingInventoryEntity ) );
        return AjaxResult.success ( page );
    }

    @Override
    public AjaxResult getKingInventorySelect ( KingInventorySelectQueryDto queryDto ) {
        queryDto.setPage ( ( queryDto.getPage () - 1 ) * queryDto.getLimit () );
        List<KingPurchaseInventorySelectVo> list = kingInventoryMapper.getKingInventorySelect ( queryDto );
        if ( ! CollectionUtils.isEmpty ( list ) ) {
            list.forEach ( inventoryVo -> {
                KingInventoryMaterialQueryDto materialQueryDto = new KingInventoryMaterialQueryDto ();
                materialQueryDto.setInventoryId ( inventoryVo.getId () );
                materialQueryDto.setMaterialDetailId ( inventoryVo.getMaterialDetailId () );
                String totalReturnNum = procureRefundMaterialService.getMaterialNumByInventoryIdAndMaterialId ( materialQueryDto );
                inventoryVo.setTotalReturnNum ( totalReturnNum );
                String totalReturnRefundNum = procureRefundMaterialService.getReturnNumByInventoryIdAndMaterialId ( materialQueryDto );
                inventoryVo.setTotalReturnRefundNum ( totalReturnRefundNum );
                OrderSumResult totalPayableResult = kingInvoicePayableDetailService.getNumAndTotalTaxPriceByInventory ( materialQueryDto );
                String totalPayableResultNum = totalPayableResult.getTotalNum ();
                List<KingInvoicePayableDetailEntity> payableDetailListByInventory = kingInvoicePayableDetailService.getInvoicePayableDetailListByInventory ( materialQueryDto );
                double sumRedNum = payableDetailListByInventory.stream ().filter ( Objects :: nonNull ).mapToDouble ( payableDetail -> Double.parseDouble ( payableDetail.getNum () ) ).sum ();
                String totalPayableNum = CommonUtil.sumStr ( totalPayableResultNum, String.valueOf ( sumRedNum ), 2 );
                inventoryVo.setTotalPayableNum ( totalPayableNum );
                String surplusPayableNum = CommonUtil.subStr ( inventoryVo.getReceiptsNum (), totalPayableNum, 2 );
                inventoryVo.setSurplusPayableNum ( surplusPayableNum );
            } );
        }
        Integer totalCount = kingInventoryMapper.queryTotalCount ( queryDto );
        PageParam records = new PageParam ();
        records.setRecords ( list ).setTotal ( totalCount );
        return AjaxResult.success ( records );
    }


    /**
     * 查询销售出库单详情
     *
     * @param id
     * @return
     */
    @Override
    public KingInventoryEntity getInventoryById ( String id ) {
        KingInventoryEntity inventoryEntity = kingInventoryMapper.getInventoryById ( id );
        if ( inventoryEntity != null ) {
            List<KingInventoryMaterialEntity> kingInventoryMaterialEntities = kingInventoryMaterialService.querySaleInventoryList ( id );
            inventoryEntity.setMaterialLists ( kingInventoryMaterialEntities );
        }
        return inventoryEntity;
    }


    /**
     * 查询销售出库单，关联各字段编码形式，推送金蝶
     * @param id
     * @return
     */
    @Override
    public SaleInventoryKingVo getInventoryCodeById ( String id ) {
        SaleInventoryKingVo saleInventoryKingVo = kingInventoryMapper.getInventoryCodeById ( id );
        return saleInventoryKingVo;
    }


}
